﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComplexNumbers
{
    public class ComplexNumber
    {
        double realPart;
        double imaginaryPart;

        public ComplexNumber(double realPart, double imaginaryPart)
        {
            this.realPart = realPart;
            this.imaginaryPart = imaginaryPart;
        }

        #region ConstructorsAndProperties

        public ComplexNumber() 
            : this(0,0)
        {
        }

        public double RealPart
        {
            get
            {
                return realPart;
            }
            set
            {
                realPart = value;
            }
        }

        public double ImaginaryPart
        {
            get
            {
                return imaginaryPart;
            }
            set
            {
                imaginaryPart = value;
            }
        }

        #endregion

        #region Operators

        public static ComplexNumber operator +(ComplexNumber a, ComplexNumber b)
        {
            ComplexNumber result = new ComplexNumber(a.realPart + b.realPart, a.imaginaryPart + b.imaginaryPart);

            return result;
        }

        public static ComplexNumber operator -(ComplexNumber a, ComplexNumber b)
        {
            ComplexNumber result = new ComplexNumber(a.realPart - b.realPart, a.imaginaryPart - b.imaginaryPart);

            return result;
        }

        public static ComplexNumber operator *(ComplexNumber a, ComplexNumber b)
        {
            double newRealPart = a.realPart*b.realPart - a.imaginaryPart*b.imaginaryPart;
            double newImaginaryPart = a.imaginaryPart * b.realPart + a.realPart * b.imaginaryPart;
            ComplexNumber result = new ComplexNumber(newRealPart, newImaginaryPart);

            return result;
        }

        public static ComplexNumber operator /(ComplexNumber a, ComplexNumber b)
        {
            double commonDenominator = (b.realPart * b.realPart + b.imaginaryPart * b.imaginaryPart);

            if (commonDenominator == 0)
            {
                throw new DivideByZeroException("Cannot divide by zero");
            }

            double newRealPart = (a.realPart * b.realPart + a.imaginaryPart * b.imaginaryPart) / commonDenominator;
            double newImaginaryPart = (a.imaginaryPart * b.realPart - a.realPart * b.imaginaryPart) / commonDenominator;

            ComplexNumber result = new ComplexNumber(newRealPart, newImaginaryPart);


            return result;
        }

        public static explicit operator double(ComplexNumber num)
        {
            return num.realPart;
        }

        public static implicit operator ComplexNumber(double num)
        {
            ComplexNumber result = new ComplexNumber(num, 0);

            return result;
        }

        #endregion

        #region Indexer

        public double this[int index]
        {
            get
            {
                if (index < 0 || index > 1)
                {
                    throw new IndexOutOfRangeException("Index must be 0 or 1.");
                }

                double result = 0;

                switch (index)
                {
                    case 0:
                        result = realPart;
                        break;
                    case 1:
                        result = imaginaryPart;
                        break;
                }

                return result;
            }
            set
            {
                if (index < 0 || index > 1)
                {
                    throw new IndexOutOfRangeException("Index must be 0 or 1.");
                }

                switch (index)
                {
                    case 0:
                        realPart = value;
                        break;
                    case 1:
                        imaginaryPart = value;
                        break;
                }
            }
        }

        #endregion

        public override string ToString()
        {
            StringBuilder printable = new StringBuilder();

            printable.Append(realPart.ToString());

            if (imaginaryPart < 0)
            {
                printable.Append(printable.Append(imaginaryPart.ToString()));
            }
            else
            {
                printable.Append("+");
                printable.Append(imaginaryPart);
            }

            printable.Append("i");

            return printable.ToString();
        }
    }
}
